package com.xbongbong.paas.service.impl;

import com.alibaba.dingtalk.openapi.helper.Env;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.outLink.domain.entity.OuterLinkConfigEntity;
import com.xbongbong.outLink.domain.entity.OuterLinkEntity;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.TimeConstant;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.OuterLinkAddRemoveAttrEnum;
import com.xbongbong.paas.enums.OuterLinkFilterRemoveAttrEnum;
import com.xbongbong.paas.enums.OuterLinkShareRemoveAttrEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.enums.SheetTypeEnum;
import com.xbongbong.paas.enums.clazz.ConditionClass;
import com.xbongbong.paas.feign.WorkOrderClient;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.SubFormPoJo;
import com.xbongbong.paas.help.FormDataListSearchHelp;
import com.xbongbong.paas.help.FormDataValidateDataHelp;
import com.xbongbong.paas.help.FormExplainHelp;
import com.xbongbong.sys.help.PackageHelp;
import com.xbongbong.paas.help.ProFormHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.model.OuterLinkConfigModel;
import com.xbongbong.paas.model.OuterLinkModel;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.outerlink.interfaces.PaasOuterLinkConfigService;
import com.xbongbong.paas.pojo.OutLinkFieldAttrEntity;
import com.xbongbong.paas.pojo.dto.ActiveRuleDTO;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataGetDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.OuterLinkAddDTO;
import com.xbongbong.paas.pojo.dto.OuterLinkAddGetDTO;
import com.xbongbong.paas.pojo.dto.OuterLinkAppearanceGetDTO;
import com.xbongbong.paas.pojo.dto.OuterLinkBaseDTO;
import com.xbongbong.paas.pojo.dto.OuterLinkListDTO;
import com.xbongbong.paas.pojo.dto.ParseSingleRowDataDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.vo.AfterSaveVO;
import com.xbongbong.paas.pojo.vo.FormDataAddGetVO;
import com.xbongbong.paas.pojo.vo.FormDataAddVO;
import com.xbongbong.paas.pojo.vo.FormDataGetVO;
import com.xbongbong.paas.pojo.vo.FormDataUpdateGetVO;
import com.xbongbong.paas.pojo.vo.PaasFormDataEsListVO;
import com.xbongbong.paas.pojo.vo.ParseSingleRowDataVO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisConstant;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.service.OuterLinkService;
import com.xbongbong.paas.service.ProModelService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.util.URLEncodeUtils;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.parent.explain.FormDataAddFormExplainHandlerName;
import com.xbongbong.parent.parse.data.FormDataListAnalysisDataHelp;
import com.xbongbong.parent.parse.data.FormDataUpdateGetAnalysisDataHelp;
import com.xbongbong.pro.businessdata.pojo.dto.FormatExplainDTO;
import com.xbongbong.pro.config.ProBaseConfig;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.domain.entity.FormConfigEntity;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.PackageStatusEnum;
import com.xbongbong.pro.enums.PackageTypeEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.ValueAddedTypeEnum;
import com.xbongbong.pro.enums.errorcodes.BuinessDefaultErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.OutLinkErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.form.pojo.dto.ChildProductDTO;
import com.xbongbong.pro.form.pojo.dto.FormConfigGetDTO;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.formdata.pojo.SaasSpecialParamPojo;
import com.xbongbong.pro.formdata.pojo.dto.SaasAnalysisDataDTO;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.pro.formexplain.pojo.vo.HandlerExplainVO;
import com.xbongbong.pro.outLink.pojo.OuterLinkAppearanceGetVO;
import com.xbongbong.pro.purchaseinvoice.dto.PurchaseInvoiceAmountDetailGetDTO;
import com.xbongbong.pro.purchaseinvoice.vo.PurchaseInvoiceAmountDetailVO;
import com.xbongbong.pro.statistic.result.pojo.ElasticAggsPojo;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.InvoiceConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.InvoiceRelationshipEntity;
import com.xbongbong.saas.domain.entity.ProductCategoryEntity;
import com.xbongbong.saas.domain.entity.WorkOrderEntity;
import com.xbongbong.saas.domain.entity.WorkOrderExplainEntity;
import com.xbongbong.saas.domain.entity.ext.WorkOrderFormEntityExt;
import com.xbongbong.saas.enums.DingtalkPageUrlEnum;
import com.xbongbong.saas.enums.FormConfigEnum;
import com.xbongbong.saas.enums.NumberTypeEnum;
import com.xbongbong.saas.enums.OutLinkAdvancedEnum;
import com.xbongbong.saas.enums.OutLinkSettingTypeEnum;
import com.xbongbong.saas.enums.OuterLinkTypeEnum;
import com.xbongbong.saas.enums.RepeatTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerCommunicateEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.InvoiceEnum;
import com.xbongbong.saas.enums.business.PaySheetEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.PurchaseEnum;
import com.xbongbong.saas.enums.business.PurchaseInvoiceEnum;
import com.xbongbong.saas.enums.business.QuotationEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.enums.business.SupplierCommunicateEnum;
import com.xbongbong.saas.enums.business.WorkReportTypeEnum;
import com.xbongbong.saas.help.FundHelp;
import com.xbongbong.saas.help.InvoiceCommonHelp;
import com.xbongbong.saas.help.InvoiceCommonHelper;
import com.xbongbong.saas.help.SaasAddHelp;
import com.xbongbong.saas.help.SaasGetHelp;
import com.xbongbong.saas.help.SaasListHelp;
import com.xbongbong.saas.help.SaasSaveHelp;
import com.xbongbong.saas.help.SaasUpdateHelp;
import com.xbongbong.saas.model.FormConfigModel;
import com.xbongbong.saas.model.IndexTypeModel;
import com.xbongbong.saas.model.InvoiceRelationshipModel;
import com.xbongbong.saas.model.PaasFormDataModel;
import com.xbongbong.saas.model.PayPlanSheetModel;
import com.xbongbong.saas.model.ProductCategoryModel;
import com.xbongbong.saas.model.WorkOrderExplainModel;
import com.xbongbong.saas.model.WorkOrderFormModel;
import com.xbongbong.saas.model.WorkOrderModel;
import com.xbongbong.saas.service.ProductService;
import com.xbongbong.saas.service.PurchaseInvoiceService;
import com.xbongbong.saas.service.WorkOrderFormDataService;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import com.xbongbong.saas.service.toolbox.help.PackageStatusHelp;
import com.xbongbong.saas.service.toolbox.help.SaasSaveHelper;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getIntegerOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;

/**
 * @author long.rao
 * @version v1.0
 * @date 2020/8/10 10:52
 * @since v1.0
 */
@Service("outerLinkService")
public class OuterLinkServiceImpl implements OuterLinkService {
    private static final Logger LOG = LoggerFactory.getLogger(OuterLinkServiceImpl.class);

    private static final List<Integer> FILTER_ATTR = Arrays.asList(FieldTypeEnum.TEXT.getType(), FieldTypeEnum.NUM.getType(), FieldTypeEnum.DATETIME.getType(), FieldTypeEnum.RADIO_GROUP.getType(),
            FieldTypeEnum.COMBO.getType(), FieldTypeEnum.ADDRESS.getType(), FieldTypeEnum.SERIALNO.getType(), FieldTypeEnum.COMBO_CHECK.getType(), FieldTypeEnum.LABEL.getType());

    @Resource
    private FormDataListSearchHelp formDataListSearchHelp;
    @Resource
    private OuterLinkModel outerLinkModel;
    @Resource
    private WorkOrderFormDataService workOrderFormDataService;
    @Resource
    private SaasSaveHelp saasSaveHelp;
    @Resource
    private FormDataValidateDataHelp formDataValidateDataHelp;
    @Resource
    private SaasSaveHelper saasSaveHelper;
    @Resource
    private OuterLinkConfigModel outerLinkConfigModel;
    @Resource
    private PaasOuterLinkConfigService outerLinkConfigService;
    @Resource
    private SaasGetHelp saasGetHelp;
    @Resource
    private PaasFormDataModel paasFormDataModel;
    @Resource
    private SaasUpdateHelp saasUpdateHelp;
    @Resource
    private FormExplainHelp formExplainHelp;
    @Resource
    private FundHelp fundHelp;
    @Resource
    private SaasListHelp saasListHelp;
    @Resource
    private InvoiceRelationshipModel invoiceRelationshipModel;
    @Resource
    private InvoiceCommonHelper invoiceCommonHelper;
    @Resource
    private WorkOrderExplainModel workOrderExplainModel;
    @Resource
    private FormDataUpdateGetAnalysisDataHelp formDataUpdateGetAnalysisDataHelp;
    @Resource
    private PurchaseInvoiceService purchaseInvoiceService;
    @Resource
    private PayPlanSheetModel payPlanSheetModel;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private SaasAddHelp saasAddHelp;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private FormDataAddFormExplainHandlerName formDataAddFormExplainHandlerName;
    @Resource
    private FormConfigModel formConfigModel;
    @Resource
    private PaasRedisHelper paasRedisHelper;
    @Resource
    private ProModelService proModelService;
    @Resource
    private PackageStatusHelp packageStatusHelp;
    @Resource
    private PackageHelp packageHelp;
    @Resource
    private EsHelper esHelper;
    @Resource
    private ProductCategoryModel productCategoryModel;
    @Resource
    private WorkOrderFormModel workOrderFormModel;
    @Resource
    private WorkOrderModel workOrderModel;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    @Resource
    private FormDataListAnalysisDataHelp formDataListAnalysisDataHelp;
    @Resource
    private ProFormHelp proFormHelp;
    @Resource
    private ProductService productService;
    @Resource
    private ProBaseConfig proBaseConfig;
    @Resource
    private IndexTypeModel indexTypeModel;
    @Resource
    private WorkOrderClient workOrderClient;


    @Override
    public PaasFormDataEsListVO getList(OuterLinkListDTO outerLinkDTO) throws XbbException {
        String token = outerLinkDTO.getToken();
        OuterLinkEntity searchEntity = outerLinkModel.getByTokenAndType(token, OuterLinkTypeEnum.SEARCH.getCode());
        if (!Objects.equals(searchEntity.getEnable(), BasicConstant.ONE)) {
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405005);
        }
        String corpid = searchEntity.getCorpid();
        Long formId = searchEntity.getFormId();
        Integer businessType = searchEntity.getBusinessType();
        Integer saasMark = SaasMarkEnum.SAAS.getCode();
        //校验套餐类型
        Integer feeType = packageHelp.getFeeType(corpid);
        if (Objects.equals(feeType,PackageTypeEnum.STANDARD.getType())){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405014);
        }
        if (Objects.equals(businessType, 0)) {
            saasMark = SaasMarkEnum.PAAS.getCode();
        }
        FormDataListDTO formDataListDTO = new FormDataListDTO();
        BeanUtil.copyProperties(outerLinkDTO, formDataListDTO);
        formDataListDTO.setCorpid(corpid);
        formDataListDTO.setBusinessType(businessType);
        formDataListDTO.setSaasMark(saasMark);
        formDataListDTO.setSubBusinessType(businessType);
        formDataListDTO.setFormId(formId);
        // 数据
        PaasFormDataEsListVO outerLinkListVO = formDataListSearchHelp.getOuterLinkList(formDataListDTO,token);
        List<FieldAttrEntity> headList = outerLinkListVO.getHeadList();
        List<String> screens = getScreens(corpid, formId, headList);
        outerLinkListVO.setScreens(screens);
        Map<String, List<ConditionClass>> conditionMap = getConditionList();
        outerLinkListVO.setConditionList(conditionMap);

        return outerLinkListVO;
    }

    @Override
    public FormDataUpdateGetVO get(OuterLinkBaseDTO outerLinkBaseDTO) throws XbbException {
        FormDataUpdateGetVO formDataUpdateGetVO = new FormDataUpdateGetVO();
        String token = outerLinkBaseDTO.getToken();
        OuterLinkEntity shareEntity = outerLinkModel.getByTokenAndType(token, OuterLinkTypeEnum.SHARE.getCode());
        String corpid = shareEntity.getCorpid();
        Long formId = shareEntity.getFormId();
        Integer saasMark = SaasMarkEnum.SAAS.getCode();
        Long dataId = shareEntity.getDataId();
        //校验套餐类型
        Integer feeType = packageHelp.getFeeType(corpid);
        if (Objects.equals(feeType,PackageTypeEnum.STANDARD.getType())){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405014);
        }
        // 因为工作报告的总的业务类型是2101，所以不用shareEntity里的businessType，而是用具体业务的outerLink的businessType
        Integer businessType = shareEntity.getBusinessType();
        if (Objects.equals(businessType, 0)) {
            saasMark = SaasMarkEnum.PAAS.getCode();
        }
        //外链分享dataId为0
        OuterLinkEntity outerLink = outerLinkModel.getOuterLink(formId, OuterLinkTypeEnum.SHARE.getCode(), corpid, 0L);
        if (Objects.isNull(outerLink) || !Objects.equals(outerLink.getEnable(), BasicConstant.ONE)) {
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405003);
        }
        outerLinkBaseDTO.setDataId(dataId);
        outerLinkBaseDTO.setFormId(formId);
        outerLinkBaseDTO.setBusinessType(businessType);
        outerLinkBaseDTO.setCorpid(corpid);
        boolean multiSpec = false;
        boolean enableMultiUnit = false;
        if ( Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode()) ) {
            // 产品编辑的时候一定要传父产品的id
            PaasFormDataEntityExt productEntity = saasGetHelp.getFormData(dataId, corpid, XbbRefTypeEnum.PRODUCT.getCode());
            if ( productEntity == null ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
            }
            JSONObject productData = productEntity.getData();
            Long parentId = productData.getLong(ProductEnum.PARENT_ID.getAttr());
            if ( !Objects.equals(parentId, 0L) ) {
                dataId = parentId;
            }
            // 是否是多单位
            enableMultiUnit = Objects.equals(productData.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), BasicConstant.ONE);
            // 是否是多规格
            Integer advancedMode = getIntegerOrDefaultFromFormData(productData, ProductEnum.SPECIFICATION.getAttr(), 0);
            multiSpec = Objects.equals(advancedMode, 1);
        }
        SaasSpecialParamPojo saasSpecialParamPojo = new SaasSpecialParamPojo();
        try {
            //先获取data数据
            PaasFormDataEntityExt formData = new PaasFormDataEntityExt();
            if ( Objects.equals(saasMark, SaasMarkEnum.SAAS.getCode()) ) {
                if (Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER.getCode())) {
                    WorkOrderEntity workOrderEntity = workOrderModel.getByKey(dataId, corpid);
                    if (Objects.nonNull(workOrderEntity)) {
                        BeanUtil.copyProperties(workOrderEntity, formData);
                    }
                    JSONObject data = formData.getData();
                    data.put(FieldTypeEnum.CLOSETIME.getAlias(),workOrderEntity.getCloseTime());
                    data.put(FieldTypeEnum.ENDTIME.getAlias(),workOrderEntity.getEndTime());
                    formData.setData(data);
                } else if (Objects.equals(businessType, XbbRefTypeEnum.RECEIPT_ORDER.getCode())) {
                    String result;
                    try {
                        FormDataGetDTO formDataGetDTO = new FormDataGetDTO();
                        BeanUtils.copyProperties(outerLinkBaseDTO, formDataGetDTO);
                        formDataGetDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
                        result = workOrderClient.getFormData(formDataGetDTO, LocaleContextHolder.getLocale().toString());
                    } catch (Exception e) {
                        LOG.error("获取表单数据报错", e);
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, I18nStringConstant.FORM_DATA_ERROR);
                    }
                    JSONObject resultObj = JsonHelperUtil.parseObject(result);
                    if (ErrorCodeEnum.API_SUCCESS.getCode() != (int)resultObj.get(StringConstant.CODE)) {
                        throw new XbbException(resultObj.getIntValue(StringConstant.CODE),resultObj.getString(StringConstant.KEY_ERROR_MSG));
                    }
                    FormDataGetVO formDataGetVO = JsonHelperUtil.parseObject(resultObj.getString("result"),FormDataGetVO.class);
                    formData = formDataGetVO.getFormList();
                }
                else {
                    formData = saasUpdateHelp.getFormData(dataId, corpid, businessType);
                }
            } else {
                // 没有saasMark标志的，现在全按paas应用来处理
                formData = paasFormDataModel.getByKey(dataId, corpid);
            }
            if (formData == null) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
            }
            if (Objects.equals(formData.getDel(),DelEnum.DELETE.getDel())) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404);

            }
            if ( FlowStatusEnum.inApproval(formData.getFlowStatus()) ) {
                throw new XbbException(BuinessDefaultErrorCodeEnum.API_ERROR_200023);
            }

            PaasFormEntityExt paasFormEntityExt = new PaasFormEntityExt();
            if (Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER.getCode())) {
                //工单
                WorkOrderFormEntityExt workOrderFormEntity = workOrderFormModel.getByKey(formId, corpid);
                if (workOrderFormEntity == null || workOrderFormEntity.getDel() == 1) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_NOT_EXIST);
                }
                BeanUtil.copyProperties(workOrderFormEntity, paasFormEntityExt);
                paasFormEntityExt.setSaasMark(SaasMarkEnum.SAAS.getCode());
                paasFormEntityExt.setBusinessType(XbbRefTypeEnum.WORK_ORDER.getCode());
            } else {
                //其他
                paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
                if (Objects.isNull(paasFormEntityExt)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_NOT_EXIST);
                }
            }
            if ( paasFormEntityExt == null ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
            }
            formDataUpdateGetVO.setPaasFormEntity(paasFormEntityExt);
            PaasFormExplainEntity paasFormExplainEntity = new PaasFormExplainEntity();
            if (Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER.getCode())) {
                //工单
                WorkOrderExplainEntity workOrderExplainEntity = workOrderExplainModel.getByFormId(formId, corpid);
                if (Objects.isNull(workOrderExplainEntity)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
                }
                BeanUtil.copyProperties(workOrderExplainEntity, paasFormExplainEntity);
            } else {
                //其他
                paasFormExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
                if (Objects.isNull(paasFormExplainEntity)) {
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
                }
            }
            List<FieldAttrEntity> explainList = new ArrayList<>();
            // 获取字段解释信息，并且过滤不可见字段
            if (Objects.nonNull(paasFormExplainEntity) && StringUtil.isNotEmpty(paasFormExplainEntity.getExplains())) {
                explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
            }

            ExplainUtil.filterSpecialAttr(explainList, OuterLinkTypeEnum.SHARE.getCode(), null);
            // 过滤各业务特殊字段
            List<String> attrList = OuterLinkShareRemoveAttrEnum.getAttrList(businessType);

            OuterLinkConfigEntity permissionSetting = outerLinkConfigService.getOuterLinkConfigEntities(corpid, formId, OuterLinkTypeEnum.SHARE.getCode(), OutLinkSettingTypeEnum.PERMISSION_SETTING.getCode());
            // 外链查询处理可见可编辑
            ExplainUtil.handelFieldPermission(explainList, permissionSetting, null);

            if (CollectionsUtil.isNotEmpty(attrList)) {
                explainList.removeIf(item -> attrList.contains(item.getAttr()));
            }
            if (CollectionsUtil.isNotEmpty(explainList)) {
                JSONObject newData = new JSONObject();
                JSONObject data = formData.getData();
                explainList.forEach(item->{
                    newData.put(item.getAttr(),data.get(item.getAttr()));
                });
                formData.setData(newData);
            }

            //确认是否为创建回款单
            SheetTypeEnum sheetTypeEnum = SheetTypeEnum.getByBusinessType(businessType);
            boolean sheetFlag = SheetTypeEnum.validateSheet(sheetTypeEnum);
            if (sheetFlag) {
                //如果是回/付款单、其他收入/支出单，则根据数据data内的回/付款单/其他收入/支出单类型重置sheetTypeEnum（前端传过来的businessType可能没有详细区分哪种类型回/付款单/其他收入/支出单）
                sheetTypeEnum = fundHelp.getSheetTypeEnumByData(sheetTypeEnum, formData.getData());
                fundHelp.handlePaymentSheet(false, sheetTypeEnum, explainList, corpid, paasFormEntityExt.getDistributorMark());
            }

            List<FieldAttrEntity> headList = explainList;

            Map<String, FieldAttrEntity> explainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (FieldAttrEntity fieldAttrEntity : headList) {
                fieldAttrEntity.setItems(proFormHelp.setItem(fieldAttrEntity, paasFormEntityExt));
                explainMap.put(fieldAttrEntity.getAttr(), fieldAttrEntity);
            }

            formDataUpdateGetVO.setExplainList(headList);

            JSONObject data = formData.getData();
            if (Objects.equals(saasMark, SaasMarkEnum.SAAS.getCode())) {
                SaasAnalysisDataDTO saasAnalysisDataDTO = new SaasAnalysisDataDTO();
                BeanUtil.copyProperties(outerLinkBaseDTO, saasAnalysisDataDTO);
                // saas特殊格式转换
                saasAnalysisDataDTO.setExplainMap(explainMap);
                saasAnalysisDataDTO.setBusinessType(businessType);
                saasAnalysisDataDTO.setFromOuterLink(BasicConstant.ONE);
                saasUpdateHelp.formatData(saasAnalysisDataDTO, data);

                if (Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_COMMUNICATE.getCode())) {
                    if (data.containsKey(CustomerCommunicateEnum.AT_USERNAME.getAttr())) {
                        JSONArray jsonArray = data.getJSONArray(CustomerCommunicateEnum.AT_USERNAME.getAttr());
                        if (jsonArray.size() <= 0) {
                            data.remove(CustomerCommunicateEnum.AT_USERNAME.getAttr());
                        }
                    }
                } else if (data.containsKey(SupplierCommunicateEnum.AT_USERNAME.getAttr())) {
                    if (data.containsKey(SupplierCommunicateEnum.AT_USERNAME.getAttr())) {
                        JSONArray jsonArray = data.getJSONArray(SupplierCommunicateEnum.AT_USERNAME.getAttr());
                        if (jsonArray.size() <= 0) {
                            data.remove(SupplierCommunicateEnum.AT_USERNAME.getAttr());
                        }
                    }
                } else if (Objects.equals(businessType, XbbRefTypeEnum.RECEIPT_ORDER.getCode())) {
                    List<String> remove = OuterLinkFilterRemoveAttrEnum.getAttrList(businessType);
                    headList.removeIf(head -> remove.contains(head.getAttr()));
                }

                // 编辑时saas字段显示特殊逻辑
                FormatExplainDTO formatExplainDTO = new FormatExplainDTO();
                BeanUtil.copyProperties(outerLinkBaseDTO, formatExplainDTO);
                formatExplainDTO.setExplainList(formDataUpdateGetVO.getExplainList());
                formatExplainDTO.setDataEntity(formData);
                formatExplainDTO.setResult(data);
                formatExplainDTO.setFromCopy(false);
                formExplainHelp.formatExplain(formatExplainDTO, data);
                // saas特殊返回字段，放在一个对象中
                saasUpdateHelp.formatSaasAttrToReturn(formDataUpdateGetVO, businessType, data);
            }

            data.put(FieldTypeEnum.SERIALNO.getAlias(), formData.getSerialNo());
            data.put(FieldTypeEnum.ADDTIME.getAlias(), formData.getAddTime());
            data.put(FieldTypeEnum.UPDATETIME.getAlias(), formData.getUpdateTime());
            // 解析数据信息
            ParseSingleRowDataDTO parseSingleRowDataDTO = new ParseSingleRowDataDTO();
            BeanUtil.copyProperties(outerLinkBaseDTO, parseSingleRowDataDTO);
            parseSingleRowDataDTO.setDataJsonObject(data);
            parseSingleRowDataDTO.setExplainMap(explainMap);
            parseSingleRowDataDTO.setOuterLink(true);
            ParseSingleRowDataVO parseSingleRowDataVO = formDataUpdateGetAnalysisDataHelp.parseSingleRowData(parseSingleRowDataDTO);
            if ( parseSingleRowDataVO == null ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.PARSE_SINGLE_ROW_DATA_FAILED);
            }
            JSONObject result = parseSingleRowDataVO.getResult();

            if ( Objects.equals(businessType, XbbRefTypeEnum.INVOICE.getCode()) ) {
                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put("invoiceId", dataId);
                param.put("isCancel", result.getInteger(InvoiceEnum.IS_CANCEL.getAttr()));
                param.put("del", DelEnum.NORMAL.getDel());
                List<InvoiceRelationshipEntity> invoiceRelationshipEntityList = invoiceRelationshipModel.findEntitys(param);

                Integer isRed = getIntegerOrDefaultFromFormData(data,InvoiceEnum.IS_RED.getAttr(),BasicConstant.ZERO);
                JSONArray amountDetail = saasListHelp.getMoneyDetail(invoiceRelationshipEntityList, result, dataId, corpid, 0, BasicConstant.ONE,isRed);
                result.put(PaasConstant.AMOUNTDETAIL, amountDetail);
                if(Objects.equals(isRed,BasicConstant.ONE)) {
                    saasSpecialParamPojo.setFormRedEdit(BasicConstant.ONE);
                }

                formDataUpdateGetVO.setSaasSpecialParamPojo(saasSpecialParamPojo);
            }
            if (Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode())) {
                // 因为前端用编辑页面来处理外链分享详情页，产品分类在编辑产品时会请求接口查询分类
    
                ChildProductDTO childProductDTO = new ChildProductDTO();
                childProductDTO.setCorpid(corpid);
                childProductDTO.setParentProductId(Collections.singletonList(dataId));
                PaasFormDataEsListVO esDataList = productService.getChildProductList(childProductDTO);
                List<PaasFormDataEntityExt> childProductList = esDataList.getPaasFormDataESList();
                List<PaasFormDataEntityExt> multiProductList = new ArrayList<>();
                Map<Long, Object> multiProductsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                // 所以这边将分类改成数字类型，并且这边将数据渲染好，就不会让分类字段额外查询接口了
                List<FieldAttrEntity> explains = formDataUpdateGetVO.getExplainList();
                for (FieldAttrEntity fieldAttrEntity : explains) {
                    String attr = fieldAttrEntity.getAttr();
                    if (Objects.equals(attr, ProductEnum.CATEGORY_ID.getAttr())) {
                        fieldAttrEntity.setFieldType(FieldTypeEnum.TEXT.getType());
                        Long categoryId = null;
                        if (Objects.nonNull(result)) {
                            String name = "";
                            try {
                                categoryId = result.getLong(ProductEnum.CATEGORY_ID.getAttr());
                                Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                                map.put("corpid",corpid);
                                map.put("del",0);
                                map.put("id",categoryId);
                                List<ProductCategoryEntity> categoryEntityList = productCategoryModel.findEntitys(map);
                                if (CollectionsUtil.isNotEmpty(categoryEntityList)) {
                                    name = categoryEntityList.get(0).getName();
                                }
                            } catch (Exception e) {
                                LOG.error("outerLinkServiceImpl.get解析产品外链分享分类出错", e);
                            }
                            if(categoryId!=null){
                                result.put(ProductEnum.CATEGORY_ID.getAttr(), name);
                            }

                        }
                    } else if(Objects.equals(attr, ProductEnum.COST.getAttr())){
                        String priceStr;
                        if (multiSpec) {
                            // 将子产品按照价格排序
                            priceStr = productService.getPriceOrCostRegion(childProductList, attr, fieldAttrEntity.getAccuracy());
                        } else {
                            Double price = getDoubleOrDefaultFromFormData(childProductList.get(0).getData(), attr, 0D);
                            priceStr = attrDecimalPrecisionHelper.formatMoneyPrecision(price, fieldAttrEntity);
                        }
                        result.put(attr, priceStr);
                    } else if (Objects.equals(attr, ProductEnum.PRICE.getAttr())){
                        int priceAccuracy = fieldAttrEntity.getAccuracy() == null ? AttrDecimalPrecisionHelper.DEFAULT_PRECISION : fieldAttrEntity.getAccuracy();
                        if (enableMultiUnit) {
                            productService.handleMultiPrice(multiProductsMap, multiProductList,corpid, dataId, priceAccuracy);
                        }
                        String priceStr;
                        if (enableMultiUnit) {
                            //多单位产品都需要做价格排序
                            priceStr = productService.getPriceOrCostRegion(multiProductList, attr, fieldAttrEntity.getAccuracy());
                        } else if (multiSpec) {
                            // 将子产品按照价格排序
                            priceStr = productService.getPriceOrCostRegion(childProductList, attr, fieldAttrEntity.getAccuracy());
                        } else {
                            Double price = getDoubleOrDefaultFromFormData(childProductList.get(0).getData(), attr, 0D);
                            priceStr = attrDecimalPrecisionHelper.formatMoneyPrecision(price, fieldAttrEntity);
                        }
                        result.put(attr, priceStr);
                    }
                }
            }
            if(Objects.equals(businessType, XbbRefTypeEnum.PURCHASE_INVOICE.getCode())){
                PurchaseInvoiceAmountDetailGetDTO purchaseInvoiceAmountDetailGetDTO = InvoiceCommonHelp.getAmountDetailByInvoiceData(formData);
                BeanUtil.copyProperties(outerLinkBaseDTO,purchaseInvoiceAmountDetailGetDTO);
                purchaseInvoiceAmountDetailGetDTO.setIsEdit(BasicConstant.ONE);
                JSONArray originObject = data.getJSONArray(PurchaseInvoiceEnum.ORIGIN_ID.getAttr());
                Long originId = 0L;
                if(Objects.nonNull(originObject)){
                    originId = originObject.getJSONObject(BasicConstant.ZERO).getLong(BasicConstant.ID);
                }

                if(originId > 0L){
                    purchaseInvoiceAmountDetailGetDTO.setFormRed(BasicConstant.ONE);
                }
                PurchaseInvoiceAmountDetailVO purchaseInvoiceAmountDetailVO = purchaseInvoiceService.getPurchaseInvoiceAmountDetail(purchaseInvoiceAmountDetailGetDTO);
                if(Objects.equals(purchaseInvoiceAmountDetailGetDTO.getIsEdit(),BasicConstant.ONE) && Objects.equals(purchaseInvoiceAmountDetailGetDTO.getIsRed(),BasicConstant.ONE)){
                    if (Objects.nonNull(result)) {
                        double invoiceAmount = result.getDouble(PurchaseInvoiceEnum.TOTAL_MONEY.getAttr());
                        result.put(PurchaseInvoiceEnum.TOTAL_MONEY.getAttr(), -invoiceAmount);
                    }
                }
                JSONArray amountDetail = JSONArray.parseArray(JSONArray.toJSONString(purchaseInvoiceAmountDetailVO.getAmountDetail()));
                JSONArray paySheetArray = data.getJSONArray(PurchaseInvoiceEnum.PAY_SHEET_ID.getAttr());
                List<Long> paySheetiList = new ArrayList<>();
                if(CollectionsUtil.isNotEmpty(paySheetArray)){
                    for(int i=0;i<paySheetArray.size();i++){
                        JSONObject paySheetObject = paySheetArray.getJSONObject(i);
                        paySheetiList.add(paySheetObject.getLong(BasicConstant.ID));
                    }
                    Map<Long,String> paySheetTypeMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    map.put("corpid",corpid);
                    map.put("idIn",paySheetiList);
                    map.put("del", BasicConstant.ZERO);
                    List<PaasFormDataEntityExt> paySheetEntityList = payPlanSheetModel.findEntitys(map);
                    paySheetEntityList.forEach(item -> {
                        JSONObject jsonObject = item.getData();
                        String paySheetType = jsonObject.getString(PaySheetEnum.PAY_SHEET_TYPE.getAttr());
                        paySheetTypeMap.put(item.getId(),paySheetType);
                    });
                    for(int i=0;i<paySheetArray.size();i++){
                        JSONObject paySheetObject = paySheetArray.getJSONObject(i);
                        String paySheetType = paySheetTypeMap.getOrDefault(paySheetObject.getLong(BasicConstant.ID),"");
                        paySheetObject.put(InvoiceConstant.PAY_SHEET_TYPE,paySheetType);
                    }
                }
                result.put(PaasConstant.AMOUNTDETAIL, amountDetail);
            }
            if (sheetFlag) {
                // TODO 这个什么东西
                /*JSONArray amountDetail = getAmountDetail4exist(sheetTypeEnum, parseSingleRowDataDTO, corpid, formDataId, formData);
                result.put(PaasConstant.AMOUNTDETAIL, amountDetail);*/
            }
            //现在前端只需要计算重复金额：重复金额为回款计划的已收款部分
            if ( Objects.equals(businessType, XbbRefTypeEnum.CONTRACT.getCode()) || Objects.equals(businessType, XbbRefTypeEnum.PURCHASE.getCode())) {
                // TODO 这个什么东西
                //Double writeOffAmount = fundMoneyHelp.getCoverCalAmount(outerLinkDTO,explainMap,businessType);
                formDataUpdateGetVO.setWriteOffAmount(0D);
            }
            if(Objects.equals(businessType, XbbRefTypeEnum.PURCHASE.getCode())){
                boolean isPurchaseProductMustBelongSupplier = Objects.equals(FormConfigEnum.PURCHASE_PRODUCT_MUST_BELONG_SUPPLIER.getConfigValue(), StringConstant.POSITIVE_NUMBER);
                //可能限制供应商
                FormConfigEntity formConfigEntity = formConfigModel.getEntityByFormId(corpid,formId, FormConfigEnum.PURCHASE_PRODUCT_MUST_BELONG_SUPPLIER.getConfig());
                if (Objects.nonNull(formConfigEntity)) {
                    if (Objects.equals(formConfigEntity.getConfigValue(), StringConstant.POSITIVE_NUMBER)) {
                        isPurchaseProductMustBelongSupplier = true;
                    } else {
                        isPurchaseProductMustBelongSupplier = false;
                    }
                }
                JSONObject saasObj = new JSONObject();
                saasObj.put("purchaseProductBelongSupplier", isPurchaseProductMustBelongSupplier);
                formDataUpdateGetVO.setSaasObj(saasObj);
            }
            formatSpecialData(businessType, result, formId, corpid, explainMap);
            formData.setData(result);
            if (Objects.equals(businessType, XbbRefTypeEnum.COMMUNICATE_PLAN.getCode())) {
                // 访客计划不支持编辑，所以外链分享详情页没有编辑按钮
                formDataUpdateGetVO.setHasEditPermission(BasicConstant.ZERO);
            }
            formDataUpdateGetVO.setData(formData);
            if (Objects.equals(outerLinkBaseDTO.getPlatform(), PlatFormEnum.DINGTALK.getValue()) && Objects.equals(formDataUpdateGetVO.getHasEditPermission(), 1)) {
                if (Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode())) {
                    // 产品移动端没有编辑页面
                    formDataUpdateGetVO.setHasEditPermission(BasicConstant.ZERO);
                    return formDataUpdateGetVO;
                }
                // 移动端，有编辑按钮的才需要返回获取编辑的url
                String messageUrl = proBaseConfig.getPushFrontUrl() + "index.html?corpid=" + corpid + "&appid=" + Env.DING_XBB_APP_ID + "&dd_nav_bgcolor=ffff943e#";
                String updateGetUrl = "dingtalk://dingtalkclient/page/link?url=";
                messageUrl += String.format(DingtalkPageUrlEnum.UPDATE_GET.getUrl(), paasFormEntityExt.getAppId(), paasFormEntityExt.getMenuId(), paasFormEntityExt.getId(), paasFormEntityExt.getBusinessType(), saasMark, dataId);
                WorkReportTypeEnum byType = WorkReportTypeEnum.getByBusinessType(businessType);
                if (Objects.nonNull(byType)) {
                    messageUrl += "&saasSpecialParamPojo=edit";
                }
                updateGetUrl += URLEncodeUtils.encodeURL(messageUrl);
                formDataUpdateGetVO.setOuterUpdateGetUrl(updateGetUrl);
            }
        } catch (XbbException e) {
            LOG.error("outerLinkServiceImpl.get数据库查询表单数据出错", e);
            throw e;
        } catch (Exception e) {
            LOG.error("outerLinkServiceImpl.get数据库查询表单数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

        return formDataUpdateGetVO;
    }

    /**
     * 处理特殊字段
     *
     * @param businessType
     * @param result
     * @param formId
     * @throws
     * @author long.rao
     * @date 2020-09-08 15:42
     */
    private void formatSpecialData(Integer businessType, JSONObject result, Long formId, String corpid, Map<String, FieldAttrEntity> fieldAttrEntityMap) throws XbbException{
        try {
            Iterator<String> iterator = result.keySet().iterator();
            while (iterator.hasNext()) {
                String key = Objects.toString(iterator.next());
                FieldAttrEntity fieldAttrEntity = fieldAttrEntityMap.get(key);
                if (fieldAttrEntity == null) {
                    continue;
                }
                String saasAttr = fieldAttrEntity.getSaasAttr();
                boolean rateNumFlag = Objects.equals(ContractEnum.GROSS_PROFIT_RATE.getSaasAttr(), saasAttr)
                        || Objects.equals(ContractEnum.CASH_PROFIT_RATE.getSaasAttr(), saasAttr)
                        || Objects.equals(ContractEnum.PAY_PERCENT.getSaasAttr(), saasAttr)
                        || Objects.equals(SalesOpportunityEnum.GROSS_PROFIT_RATE.getSaasAttr(), saasAttr)
                        || Objects.equals(QuotationEnum.GROSS_PROFIT_RATE.getSaasAttr(), saasAttr)
                        || Objects.equals(PurchaseEnum.RECEINE_PERCENT.getSaasAttr(), saasAttr);
                if (Objects.equals(fieldAttrEntity.getNumberType(), NumberTypeEnum.RATE.getCode())) {
                    rateNumFlag = true;
                }
                if(Objects.equals(fieldAttrEntity.getFieldType(),FieldTypeEnum.NUM.getType()) && Objects.nonNull(result.get(key))) {
                    if ( Objects.equals(businessType, XbbRefTypeEnum.PRODUCT.getCode()) && (Objects.equals(fieldAttrEntity.getAttr(),ProductEnum.COST.getAttr())||Objects.equals(fieldAttrEntity.getAttr(),ProductEnum.PRICE.getAttr()) ) ) {
                        continue;
                    }
                    // 小数精度
                    Double value;
                    try {
                        value = result.getDoubleValue(key);
                    } catch (Exception e) {
                        value = 0D;
                    }
                    if ( !rateNumFlag ) {
                        if ( Objects.equals(fieldAttrEntity.getAmountFlag(),1) ) {
                            result.put(key,attrDecimalPrecisionHelper.formatMoneyPrecision(value, fieldAttrEntity));
                        } else {
                            result.put(key,attrDecimalPrecisionHelper.setPrecision(value, fieldAttrEntity.getAccuracy()));
                        }
                    } else {
                        String decValue = attrDecimalPrecisionHelper.setDecPrecision(value * 100, fieldAttrEntity.getAccuracy());
                        result.put(key, decValue + "%");
                    }
                }
                if (ExplainUtil.isSubForm(fieldAttrEntity.getFieldType())) {
                    JSONArray jsonArray = result.getJSONArray(key) == null ? new JSONArray() : result.getJSONArray(key);
                    JSONArray resultJsonArray = new JSONArray();
                    SubFormPoJo subForm = fieldAttrEntity.getSubForm();
                    List<? extends FieldAttrEntity> items = (subForm == null || subForm.getItems() == null) ? new ArrayList<>() : subForm.getItems();
                    Map<String, FieldAttrEntity> subExplainMap = ExplainUtil.getExplainMapByList(items);

                    for (int i = 0; i < jsonArray.size(); i++) {
                        if (!(jsonArray.get(i) instanceof Map)) {
                            continue;
                        }
                        JSONObject subJsonObject = jsonArray.getJSONObject(i);
                        Iterator subIterator = subJsonObject.keySet().iterator();
                        JSONObject subResult = new JSONObject();
                        while (subIterator.hasNext()) {
                            String subKey = Objects.toString(subIterator.next());
                            FieldAttrEntity subFieldAttrEntity = subExplainMap.get(subKey);
                            if (Objects.nonNull(subFieldAttrEntity) && Objects.equals(subFieldAttrEntity.getFieldType(), FieldTypeEnum.DATETIME.getType())) {
                                try {
                                    // 前端渲染需要正常的时间戳，但是有些时间类型的字段存的是字符串类型的时间戳，比如"1600056577",前端就不会解析，所以这边直接转一遍
                                    Long date = subJsonObject.getLong(subKey);
                                    subResult.put(subKey, date);
                                } catch (Exception e) {
                                }
                            } else {
                                subResult.put(subKey, subJsonObject.get(subKey));
                            }
                        }
                        resultJsonArray.add(subResult);
                    }
                    result.put(key, resultJsonArray);
                } else if (Objects.equals(fieldAttrEntity.getFieldType(), FieldTypeEnum.DATETIME.getType())) {
                    try {
                        // 前端渲染需要正常的时间戳，但是有些时间类型的字段存的是字符串类型的时间戳，比如"1600056577",前端就不会解析，所以这边直接转一遍
                        Long date = result.getLong(key);
                        result.put(key, date);
                    } catch (Exception e) {
                    }
                }
            }
            FormConfigGetDTO formConfigGetDTO = new FormConfigGetDTO();
            formConfigGetDTO.setCorpid(corpid);
            formConfigGetDTO.setBusinessType(businessType);
            formConfigGetDTO.setFormId(formId);
            Map<String, String> lastConnectTimeMap = formDataListAnalysisDataHelp.lastConnectTime(formConfigGetDTO);
            Long lastConnectTime;
            if (Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode())) {
                lastConnectTime = result.getLong(CustomerManagementEnum.LAST_CONNECT_TIME.getAttr());
                String configValue = lastConnectTimeMap.get(FormConfigEnum.CUSTOMER_LAST_CONNECT_TIME.getConfig());
                if (Objects.equals(configValue, "1")) {
                    result.put(CustomerManagementEnum.LAST_CONNECT_TIME.getAttr(), DateTimeUtil.getLastConnectTimeStr(lastConnectTime));
                } else {
                    result.put(CustomerManagementEnum.LAST_CONNECT_TIME.getAttr(), DateTimeUtil.getStringEpochSecond(lastConnectTime));
                }
            } else if (Objects.equals(businessType, XbbRefTypeEnum.SALES_OPPORTUNITY.getCode())) {
                lastConnectTime = result.getLong(SalesOpportunityEnum.LAST_CONNECT_TIME.getAttr());
                String configValue = lastConnectTimeMap.get(FormConfigEnum.SALES_OPPORTUNITY_LAST_CONNECT_TIME.getConfig());
                if (Objects.equals(configValue, "1")) {
                    result.put(SalesOpportunityEnum.LAST_CONNECT_TIME.getAttr(), DateTimeUtil.getLastConnectTimeStr(lastConnectTime));
                } else {
                    result.put(SalesOpportunityEnum.LAST_CONNECT_TIME.getAttr(), DateTimeUtil.getStringEpochSecond(lastConnectTime));
                }
            } else {
                return;
            }
        } catch (Exception e) {
            LOG.error("OuterLinkServiceImpl.get.formatSpecialDate 处理特殊字段报错 businessType = " + businessType + " data为 " + result.toJSONString(), e);
        }
    }

    /**
     * 获取外链筛选项
     *
     * @param corpid
     * @param formId
     * @param headList
     * @author long.rao
     * @date 2020-08-18 09:49
     */
    private List<String> getScreens(String corpid, Long formId, List<FieldAttrEntity> headList) throws XbbException{
        OuterLinkConfigEntity outerLinkConfigEntity = null;

        Map<String,Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put("type", OuterLinkTypeEnum.SEARCH.getCode());
        params.put("corpid",corpid);
        params.put("del", DelEnum.NORMAL.getDel());
        params.put("formId",formId);
        params.put("configType", OutLinkSettingTypeEnum.FILTER_SETTING.getCode());
        List<OuterLinkConfigEntity>  entityList = outerLinkConfigModel.findEntitys(params);
        if (CollectionsUtil.isNotEmpty(entityList)){
            outerLinkConfigEntity = entityList.get(0);
        }
        List<FieldAttrEntity> fields = new ArrayList<>();
        headList.forEach(item -> {
            if (FILTER_ATTR.contains(item.getFieldType())) {
                fields.add(item);
            }
        });
        List<String> screen = new ArrayList<>();
        if (Objects.isNull(outerLinkConfigEntity)){
            for (int i = 0; i < fields.size(); i++) {
                screen.add(fields.get(i).getAttr());
            }
        } else {
            List<OutLinkFieldAttrEntity> list = new ArrayList<>();
            if (StringUtil.isNotEmpty(outerLinkConfigEntity.getExplains())) {
                list = JSONArray.parseArray(outerLinkConfigEntity.getExplains(), OutLinkFieldAttrEntity.class);
            }
            list = outerLinkConfigService.syncOuterLinkField(fields,list, OuterLinkTypeEnum.SEARCH,OutLinkSettingTypeEnum.FILTER_SETTING);
            for (int i = 0; i < list.size(); i++) {
                if (Objects.equals(list.get(i).getFilterable(),1)){
                    screen.add(list.get(i).getAttr());
                }
            }
        }
        return screen;
    }


    @Override
    public FormDataAddVO add(OuterLinkAddDTO outerLinkAddDTO) throws XbbException {
        OuterLinkEntity outerLinkEntity = getTokenByType(outerLinkAddDTO.getToken(),OuterLinkTypeEnum.WRITE.getCode());
        String corpid =outerLinkEntity.getCorpid();
        Long formId = outerLinkEntity.getFormId();
        Integer businessType = outerLinkEntity.getBusinessType();
        //校验套餐类型
        Integer feeType = packageHelp.getFeeType(corpid);
        if (Objects.equals(feeType,PackageTypeEnum.STANDARD.getType())){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405014);
        }
        if (Objects.equals(businessType,0) || Objects.isNull(businessType)){
            outerLinkAddDTO.setSaasMark(SaasMarkEnum.PAAS.getCode());
        } else {
            outerLinkAddDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
        }
        outerLinkAddDTO.setCorpid(corpid);
        String expandField = outerLinkEntity.getExpandField();
        String attr = outerLinkEntity.getAttr();
        // 校验高级设置
        OuterLinkConfigEntity outerLinkConfigEntity = outerLinkConfigService.getOuterLinkConfigEntities(corpid,formId, OuterLinkTypeEnum.WRITE.getCode(),OutLinkSettingTypeEnum.ADVANCED_SETTING.getCode());
        JSONObject limit =new JSONObject();
        limit.put("enable",false);
        JSONObject  openCloseTime =new JSONObject();
        openCloseTime.put("enable",false);
        if (Objects.nonNull(outerLinkConfigEntity)){
            JSONObject jsonObject = outerLinkConfigEntity.getSeniorInfo();
            if (Objects.nonNull(jsonObject)){
                limit = jsonObject.getJSONObject("limit");
                openCloseTime = jsonObject.getJSONObject("openCloseTime");
            }
        }
        // 是否在禁止提交的时间内
        Boolean forbidden = false;
        if (Objects.nonNull(openCloseTime)){
            Long startTime = openCloseTime.getLong("startTime");
            Long endTime = openCloseTime.getLong("endTime");
            Long currentTime = DateUtil.getLong();
            if(openCloseTime.getBoolean("enable")){
                if (Objects.nonNull(startTime)){
                    forbidden = currentTime <= startTime;
                }
                if (Objects.nonNull(endTime)){
                    forbidden = currentTime >= endTime;
                }
            }
            if(forbidden){
                throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405001);
            }
        }
        // 限制提交量
        limitAdvanced(outerLinkAddDTO.getSaasMark(),corpid, formId, businessType, limit);

        // 外链数据加上拓展字段
        outerLinkAddDTO.getDataList().put(attr,expandField);

        FormDataAddVO formDataSaveVO = new FormDataAddVO();
        Integer oneStatus = packageStatusHelp.getPackageStatus(corpid, ValueAddedTypeEnum.ONE_FORM_DATA_NUM, 1);
        Integer allStatus = packageStatusHelp.getPackageStatus(corpid, ValueAddedTypeEnum.TOTAL_FORM_DATA_NUM, 1);
        if ( !Objects.equals(oneStatus, PackageStatusEnum.NORMAL.getCode()) && !Objects.equals(oneStatus, PackageStatusEnum.WARNING.getCode()) ) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100074, I18nStringConstant.SINGLE_TABLE_NUM_LIMIT);
        }

        if ( !Objects.equals(allStatus, PackageStatusEnum.NORMAL.getCode()) && !Objects.equals(allStatus, PackageStatusEnum.WARNING.getCode()) ) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100074, I18nStringConstant.TOTAL_TABLE_NUM_LIMIT);
        }
        //工单逻辑与其他业务逻辑分离，在workOrderFormDataService.add中已加异常后的es删除相关数据操作
        try {
            if ( Objects.equals(businessType, XbbRefTypeEnum.WORK_ORDER.getCode()) ) {
                //工单
                formDataSaveVO = workOrderFormDataService.addForOutLink(outerLinkAddDTO);
                return formDataSaveVO;
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("workOrderFormData 数据库保存表单数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

        try {
            PaasFormEntityExt paasFormEntityExt;
            // 工作报告从首页快捷新建获取的formId不正确，需要重新再获取下
            if (Objects.equals(businessType, XbbRefTypeEnum.WORK_REPORT.getCode())) {
                paasFormEntityExt = paasFormModel.getByBusinessType(outerLinkAddDTO.getSubBusinessType(),corpid);
            } else {
                paasFormEntityExt = paasFormModel.getByKey(outerLinkAddDTO.getFormId(), outerLinkAddDTO.getCorpid());
            }
            if ( paasFormEntityExt == null ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_DATA_NOT_EXIST);
            }
            outerLinkAddDTO.setFormId(paasFormEntityExt.getId());
            PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(outerLinkAddDTO.getFormId(), corpid);
            if ( Objects.isNull(paasFormExplainEntity) ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
            }
            JSONObject data = outerLinkAddDTO.getDataList();


            Map<String, FieldAttrEntity> explainMap = ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);

            ValidateDataDTO validateDataDTO = new ValidateDataDTO();
            BeanUtil.copyProperties(outerLinkAddDTO, validateDataDTO);
            validateDataDTO.setData(data);
            validateDataDTO.setExplainMap(explainMap);
            //销项发票、进项发票、回款单、付款单金额明细处理
            SheetTypeEnum sheetTypeEnum = SheetTypeEnum.getByBusinessType(businessType);
            JSONArray amountDetail = saasSaveHelper.getAmountDetail4Check(null, sheetTypeEnum, data,businessType);
            outerLinkAddDTO.setAmountDetail(amountDetail);
            validateDataDTO.setAmountDetail(amountDetail);
            ProSaveHelp.analyticalData(validateDataDTO);

            validateDataDTO.setFromOuterLink(BasicConstant.ONE);
//            setSpecialParam(outerLinkAddDTO, validateDataDTO);
//            formDataValidateDataHelp.validateData(validateDataDTO);
            // 外链数据对单行文本、多行文本字符限制校验
            formDataValidateDataHelp.validateOuterLinkData(data, explainMap);
            saasSaveHelp.beforeSave(validateDataDTO);

            if ( validateDataDTO.getSubBusinessType() != null ) {
                outerLinkAddDTO.setSubBusinessType(validateDataDTO.getSubBusinessType());
            }

            if ( CollectionsUtil.isNotEmpty(amountDetail) ) {
                SaasNeedRedundantAttrPojo saasNeedRedundantAttrPoJo = validateDataDTO.getSaasNeedRedundantAttrPoJo();
                saasNeedRedundantAttrPoJo.setAmountDetail(amountDetail);
            }
            outerLinkAddDTO.setSaasNeedRedundantAttrPoJo(validateDataDTO.getSaasNeedRedundantAttrPoJo());
            PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
            BeanUtil.copyProperties(outerLinkAddDTO, paasFormDataEntity);
            paasFormDataEntity.setOwnerId(PaasConstant.OUT_LINK_USER_ID);

            if ( Objects.nonNull(outerLinkAddDTO.getOwnerId()) && !outerLinkAddDTO.getOwnerId().isEmpty() ) {
                paasFormDataEntity.setOwnerId(Objects.toString(outerLinkAddDTO.getOwnerId().get(0).getId(), ""));
            }
            String serialNo = outerLinkAddDTO.getSerialNo();
            FieldAttrEntity fieldAttrEntity = explainMap.get(FieldTypeEnum.SERIALNO.getAlias());
            if (Objects.nonNull(fieldAttrEntity) && Objects.equals(fieldAttrEntity.getStrictController(), BasicConstant.ONE)){
                serialNo = saasSaveHelp.getSerialNo(corpid, formId, fieldAttrEntity);
            }
            paasFormDataEntity.setData(outerLinkAddDTO.getDataList());
            paasFormDataEntity.setSerialNo(serialNo);

            paasFormDataEntity.setMenuId(paasFormEntityExt.getMenuId());
            paasFormDataEntity.setFlowStatus(FlowStatusEnum.NOT_NEED_APPROVAL.getType());
            paasFormDataEntity.setCreatorId(PaasConstant.OUT_LINK_USER_ID);

            outerLinkAddDTO.setExplainMap(explainMap);
            FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(outerLinkAddDTO,formDataAddDTO);
            formDataAddDTO.setFromOuterLink(BasicConstant.ONE);
            AfterSaveVO afterSaveVO = proModelService.insert(formDataAddDTO, paasFormDataEntity, paasFormEntityExt);
            formDataSaveVO.setDataId(afterSaveVO.getFormDataId());
            String businessRules = paasFormEntityExt.getBusinessRules();
            if (!Objects.equals(1, outerLinkAddDTO.getIsBusinessRule()) && Objects.equals("1", businessRules)) {
                ActiveRuleDTO activeRuleDTO = new ActiveRuleDTO();
                BeanUtil.copyProperties(outerLinkAddDTO, activeRuleDTO);
                activeRuleDTO.setDataId(paasFormDataEntity.getId());
                long now = DateUtil.getInt();
                paasFormDataEntity.setAddTime(now);
                paasFormDataEntity.setUpdateTime(now);
                activeRuleDTO.setPaasFormDataEntity(paasFormDataEntity);
                activeRuleDTO.setExplainList(JSON.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class));
            }
            if ( Objects.equals(afterSaveVO.getCode(), PaasConstant.FORM_ADD_PROCESS_RETURN_CODE) ) {
                formDataSaveVO.setMsg(afterSaveVO.getMsg());
                formDataSaveVO.setCode(afterSaveVO.getCode());
            } else {
                formDataSaveVO.setMsg(I18nMessageUtil.getMessage(MessageConstant.FORM_ADD_RETURN_MSG));
                formDataSaveVO.setCode(PaasConstant.FORM_ADD_RETURN_CODE);
            }
            formDataSaveVO.setFormDataId(paasFormDataEntity.getId());

            // 更新缓存数据
            // 开启不开启限制 数据量都要计入
            String[] keys = getKeys(corpid,formId);
            for (int i = 0; i < keys.length; i++) {
                String key = keys[i];
                String value = paasRedisHelper.getValue(RedisPrefixConstant.OUT_LINK_ADVANCED, key);
                if (Objects.nonNull(value)){
                    long valueLong = Long.parseLong(value);
                    valueLong ++;
                    paasRedisHelper.removeValue(RedisPrefixConstant.OUT_LINK_ADVANCED, key);
                    paasRedisHelper.setValue(RedisPrefixConstant.OUT_LINK_ADVANCED, key,valueLong, RedisConstant.SHORT_DURATION);
                } else {
                    Integer startTime = null;
                    Integer endTime = null;
                    if (Objects.equals(i, 0)) {
                    } else if (Objects.equals(i, 1)) {
                        startTime = DateUtil.getTodayInt();
                        endTime = DateUtil.getTodayInt() + TimeConstant.SECONDS_PER_DAY;
                    } else if (Objects.equals(i, 2)) {
                        startTime = DateUtil.getFirstDateOfThisMonth();
                        endTime = DateUtil.getFirstDateOfThisMonth() + TimeConstant.SECONDS_PER_MONTH;
                    } else if (Objects.equals(i, 3)) {
                        startTime = DateUtil.getFirstDateOfYear();
                        endTime = DateUtil.getFirstDateOfYear() + TimeConstant.SECONDS_PER_YEAR;
                    }
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termQuery("formId", formId));
                    boolQueryBuilder.filter(termQuery("creatorId.keyword", -3));
                    if (Objects.nonNull(startTime) && Objects.nonNull(endTime)) {
                        boolQueryBuilder.filter(rangeQuery("addTime").gte(startTime).lt(endTime));
                    }
                    IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(corpid, businessType, outerLinkAddDTO.getSaasMark());

                    ElasticAggsPojo elasticAggsPojo = esHelper.elasticAggs(indexTypeEnum, boolQueryBuilder, null);
                    long valueLong = Long.parseLong(elasticAggsPojo.getTotal());
                    valueLong ++;
                    paasRedisHelper.setValue(RedisPrefixConstant.OUT_LINK_ADVANCED, key,valueLong, RedisConstant.SHORT_DURATION);
                }
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("paasFormData数据库保存表单数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return formDataSaveVO;

    }

    /**
     * 高级筛选限制提交量
     * @param corpid
     * @param formId
     * @param businessType
     * @param limit
     * @throws XbbException
     */
    public void limitAdvanced(Integer saasMark,String corpid, Long formId, Integer businessType, JSONObject limit) throws XbbException {
        if (Objects.nonNull(limit)) {
            if (limit.getBoolean("enable")) {
                Integer type = limit.getInteger("type");
                Integer count = limit.getInteger("count");
                String key = null;
                // 对于不同的type，key的生成规则不一样
                if (Objects.equals(type,OutLinkAdvancedEnum.TOTAL.getCode())){
                    key = OutLinkAdvancedEnum.TOTAL.getCode() + corpid + formId;
                } else if (Objects.equals(type,OutLinkAdvancedEnum.DAY.getCode())){
                    key = OutLinkAdvancedEnum.DAY.getCode() + DateUtil.getDateString(DateUtil.getInt()) + corpid + formId;
                } else if (Objects.equals(type,OutLinkAdvancedEnum.MONTH.getCode())){
                    key = OutLinkAdvancedEnum.MONTH.getCode() + DateUtil.getString(new SimpleDateFormat("yyyy-MM")) + corpid + formId;
                } else if (Objects.equals(type,OutLinkAdvancedEnum.YEAR.getCode())){
                    key = OutLinkAdvancedEnum.YEAR.getCode() + DateUtil.getNowSDFYears() + corpid + formId;
                }
                String value = paasRedisHelper.getValue(RedisPrefixConstant.OUT_LINK_ADVANCED, key);
                if (Objects.nonNull(value)) {
                    // 缓存中能拿到数据
                    long valueLong = Long.parseLong(value);
                    if (++valueLong > count) {
                        throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405002);
                    }
                } else {
                    // 缓存中拿不到数据，从db汇总
                    Integer startTime = null;
                    Integer endTime = null;
                    if (Objects.equals(type, OutLinkAdvancedEnum.TOTAL.getCode())) {
                    } else if (Objects.equals(type, OutLinkAdvancedEnum.DAY.getCode())) {
                        startTime = DateUtil.getTodayInt();
                        endTime = DateUtil.getTodayInt() + TimeConstant.SECONDS_PER_DAY;
                    } else if (Objects.equals(type, OutLinkAdvancedEnum.MONTH.getCode())) {
                        startTime = DateUtil.getFirstDateOfThisMonth();
                        endTime = DateUtil.getFirstDateOfThisMonth() + TimeConstant.SECONDS_PER_MONTH;
                    } else if (Objects.equals(type, OutLinkAdvancedEnum.YEAR.getCode())) {
                        startTime = DateUtil.getFirstDateOfYear();
                        endTime = DateUtil.getFirstDateOfYear() + TimeConstant.SECONDS_PER_YEAR;
                    }
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL, DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termQuery("formId", formId));
                    boolQueryBuilder.filter(termQuery("creatorId.keyword", -3));
                    if (Objects.nonNull(startTime) && Objects.nonNull(endTime)) {
                        boolQueryBuilder.filter(rangeQuery("addTime").gte(startTime).lt(endTime));
                    }
                    IndexTypeEnum indexTypeEnum = indexTypeModel.getIndexType(corpid, businessType, saasMark);

                    ElasticAggsPojo elasticAggsPojo = esHelper.elasticAggs(indexTypeEnum, boolQueryBuilder, null);
                    long valueLong = Long.parseLong(elasticAggsPojo.getTotal());
                    if (++valueLong > count) {
                        throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405002);
                    }
                }
            }
        }
    }

    /**
     * 获取高级设置对应key
     * @param
     * @param corpid
     * @param formId
     * @return
     */
    private String[] getKeys(String corpid,Long formId){
        String[] keyArray = new String[4];
        keyArray[0] = OutLinkAdvancedEnum.TOTAL.getCode() + corpid + formId;
        keyArray[1] = OutLinkAdvancedEnum.DAY.getCode() + DateUtil.getDateString(DateUtil.getInt()) + corpid + formId;
        keyArray[2] = OutLinkAdvancedEnum.MONTH.getCode() + DateUtil.getString(new SimpleDateFormat("yyyy-MM")) + corpid + formId;
        keyArray[3] = OutLinkAdvancedEnum.YEAR.getCode() + DateUtil.getNowSDFYears() + corpid + formId;
        return keyArray;
    }

    @Override
    public FormDataAddGetVO addGet(OuterLinkAddGetDTO outerLinkAddGetDTO) throws XbbException {
        OuterLinkEntity outerLinkEntity = getTokenByType(outerLinkAddGetDTO.getToken(),OuterLinkTypeEnum.WRITE.getCode());
        String corpid =outerLinkEntity.getCorpid();
        Long formId = outerLinkEntity.getFormId();
        Integer businessType = outerLinkEntity.getBusinessType();
        outerLinkAddGetDTO.setCorpid(corpid);
        //校验套餐类型
        Integer feeType = packageHelp.getFeeType(corpid);
        if (Objects.equals(feeType,PackageTypeEnum.STANDARD.getType())){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405014);
        }
        if (Objects.equals(businessType,0) || Objects.isNull(businessType)){
            outerLinkAddGetDTO.setSaasMark(SaasMarkEnum.PAAS.getCode());
        } else {
            outerLinkAddGetDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
        }
        FormDataAddGetVO formDataAddGetVO = new FormDataAddGetVO();

        if (!Objects.equals(outerLinkAddGetDTO.getOuterShow(), BasicConstant.ONE)) {
            // 从外观设置这里获取addGet接口不需要校验高级设置
            // 校验高级设置
            OuterLinkConfigEntity outerLinkConfig = outerLinkConfigService.getOuterLinkConfigEntities(corpid, formId, OuterLinkTypeEnum.WRITE.getCode(), OutLinkSettingTypeEnum.ADVANCED_SETTING.getCode());
            JSONObject limit = new JSONObject();
            limit.put("enable", false);
            JSONObject openCloseTime = new JSONObject();
            openCloseTime.put("enable", false);
            if (Objects.nonNull(outerLinkConfig)) {
                JSONObject jsonObject = outerLinkConfig.getSeniorInfo();
                if (Objects.nonNull(jsonObject)) {
                    limit = jsonObject.getJSONObject("limit");
                    openCloseTime = jsonObject.getJSONObject("openCloseTime");
                }
            }
            // 是否在禁止提交的时间内
            Boolean forbidden = false;
            if (Objects.nonNull(openCloseTime)) {
                Long startTime = openCloseTime.getLong("startTime");
                Long endTime = openCloseTime.getLong("endTime");
                Long currentTime = DateUtil.getLong();
                if (openCloseTime.getBoolean("enable")) {
                    if (Objects.nonNull(startTime)) {
                        forbidden = currentTime <= startTime;
                    }
                    if (Objects.nonNull(endTime)) {
                        forbidden = currentTime >= endTime;
                    }
                }
                if (forbidden) {
                    throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405001);
                }
            }
            // 限制提交量
            limitAdvanced(outerLinkAddGetDTO.getSaasMark(), corpid, formId, businessType, limit);
        }

        try {
            if ( Objects.equals(XbbRefTypeEnum.WORK_ORDER.getCode(), businessType) ) {
                //工单
                formDataAddGetVO = workOrderFormDataService.addGetForOutLink(outerLinkAddGetDTO);
                String value = formConfigModel.getConfigValueByRedis(RedisPrefixConstant.ASSIGNMENT_RULES, corpid, formId, outerLinkAddGetDTO.getSaasMark(), formDataAddGetVO.getPaasFormEntity().getBusinessType(), "0");
                if (StringUtil.isNotEmpty(value)) {
                    formDataAddGetVO.setAssignmentRules(Integer.valueOf(value));
                }
                return formDataAddGetVO;
            }
            PaasFormEntityExt paasFormEntityExt = paasFormModel.getByKey(formId, corpid);
            if ( Objects.isNull(paasFormEntityExt) ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018, MessageConstant.FORM_NOT_EXIST);
            }
            String formConfigValue = formConfigModel.getConfigValueByRedis(RedisPrefixConstant.ASSIGNMENT_RULES, corpid, formId, outerLinkAddGetDTO.getSaasMark(), paasFormEntityExt.getBusinessType(), "0");
            if (StringUtil.isNotEmpty(formConfigValue)) {
                formDataAddGetVO.setAssignmentRules(Integer.valueOf(formConfigValue));
            }
            saasAddHelp.handleFormEntity(paasFormEntityExt, 1, businessType);
            formDataAddGetVO.setPaasFormEntity(paasFormEntityExt);
            PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
            if ( Objects.isNull(paasFormExplainEntity) ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
            }
            // 获取字段解释信息，根据权限设置过滤不可见字段 start
            List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);
            ExplainUtil.filterSpecialAttr(explainList, OuterLinkTypeEnum.WRITE.getCode(), null);
            // 过滤各业务特殊字段
            List<String> attrList = OuterLinkAddRemoveAttrEnum.getAttrList(businessType);
            if (CollectionsUtil.isNotEmpty(attrList)) {
                explainList.removeIf(item -> attrList.contains(item.getAttr()));
            }
            explainList.forEach(item -> {
                item.setVisible(1);
                item.setEditable(1);
                item.setVisibleScopeEnable(0);
                item.setEditableAdvanceEnable(0);
                if (ExplainUtil.isSubFormNoSelectProduct(item.getFieldType())){
                    List<? extends FieldAttrEntity> subExplainList = item.getSubForm().getItems();
                    for (FieldAttrEntity subAttrEntity : subExplainList) {
                        subAttrEntity.setVisible(1);
                        subAttrEntity.setEditable(1);
                        subAttrEntity.setVisibleScopeEnable(0);
                        subAttrEntity.setEditableAdvanceEnable(0);
                    }
                    item.getSubForm().setItems(subExplainList);
                }
                // 阶段比例设置为不可编辑，小数位数为0位
                if(Objects.equals(item.getFieldType(),FieldTypeEnum.STAGE_RATIO.getType())){
                    item.setEditable(0);
                    item.setAccuracy(0);
                }
            });
            HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
            BeanUtil.copyProperties(outerLinkAddGetDTO, handlerExplainDTO, false);
            handlerExplainDTO.setExplainList(explainList);
            handlerExplainDTO.setPaasFormEntityExt(paasFormEntityExt);
            handlerExplainDTO.setIsOuterLink(BasicConstant.ONE);
            HandlerExplainVO handlerExplainVO = formDataAddFormExplainHandlerName.handleExplain(handlerExplainDTO);
            if ( handlerExplainVO == null ) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_NOT_EXIST);
            }
            explainList = handlerExplainVO.getHeadList();
            OuterLinkConfigEntity outerLinkConfigEntity = outerLinkConfigService.getOuterLinkConfigEntities(corpid,formId,OuterLinkTypeEnum.WRITE.getCode(),OutLinkSettingTypeEnum.PERMISSION_SETTING.getCode());
            List<String> notVisableAttr = new ArrayList<>();
            List<String> notEditableAttr = new ArrayList<>();
            Map<String,List<String>> notVisiableSubAttrMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String,List<String>> notEditableSubAttrMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (Objects.nonNull(outerLinkConfigEntity)){
                String explains = outerLinkConfigEntity.getExplains();
                List<OutLinkFieldAttrEntity> outLinkFieldAttrEntities = JSONArray.parseArray(explains,OutLinkFieldAttrEntity.class);
                for (int i = 0; i < outLinkFieldAttrEntities.size(); i++) {
                    OutLinkFieldAttrEntity entity = outLinkFieldAttrEntities.get(i);
                    //  子表单内不可见字段
                    List<String> notVisiableSubAttrList = new ArrayList<>();
                    List<String> notEditableSubAttrList = new ArrayList<>();
                    if (ExplainUtil.isSubFormNoSelectProduct(entity.getFieldType())){
                        List<OutLinkFieldAttrEntity> subExplainList = JSONObject.parseArray(JSON.toJSONString(entity.getSubForm().getItems()), OutLinkFieldAttrEntity.class);
                        subExplainList.forEach(item -> {
                            if (!Objects.equals(item.getVisible(),1)){
                                notVisiableSubAttrList.add(item.getAttr());
                            }
                            if (!Objects.equals(item.getEditable(),1)){
                                notEditableSubAttrList.add(item.getAttr());
                            }
                        });
                        notVisiableSubAttrMap.put(entity.getAttr(),notVisiableSubAttrList);
                        notEditableSubAttrMap.put(entity.getAttr(),notEditableSubAttrList);
                    }
                    if (!Objects.equals(entity.getVisible(),1)){
                        notVisableAttr.add(entity.getAttr());
                    }
                    if (!Objects.equals(entity.getEditable(),1)){
                        notEditableAttr.add(entity.getAttr());
                    }
                }
            }
            Iterator it = explainList.iterator();
            while (it.hasNext()){
                FieldAttrEntity fieldAttrEntity = (FieldAttrEntity) it.next();
                if (notVisableAttr.contains(fieldAttrEntity.getAttr())){
                    // 字段不可见 直接remove
                    it.remove();
                    continue;
                }
                if (notEditableAttr.contains(fieldAttrEntity.getAttr())){
                    fieldAttrEntity.setEditable(0);
                }
                if (ExplainUtil.isSubFormNoSelectProduct(fieldAttrEntity.getFieldType())){
                    List<? extends FieldAttrEntity> subExplainList = fieldAttrEntity.getSubForm().getItems();
                    List<String> notVisiableSubAttrList = notVisiableSubAttrMap.getOrDefault(fieldAttrEntity.getAttr(),new ArrayList<>());
                    if (Objects.equals(fieldAttrEntity.getSaasAttr(), CustomerManagementEnum.PHONE.getSaasAttr())) {
                        // 外链填写，如果电话字段不可见，不能romve，而是设置visiable为o，否则前端显示有问题
                        subExplainList.forEach(item -> {
                            if (notVisiableSubAttrList.contains(item.getAttr())){
                                item.setVisible(0);
                            }
                        });
                    } else {
                        subExplainList.removeIf(item -> notVisiableSubAttrList.contains(item.getAttr()));
                    }
                    List<String> notEditableSubList = notEditableSubAttrMap.getOrDefault(fieldAttrEntity.getAttr(),new ArrayList<>());
                    subExplainList.forEach(item -> {
                        if (notEditableSubList.contains(item.getAttr())){
                            item.setEditable(0);
                        }
                    });
                    fieldAttrEntity.getSubForm().setItems(subExplainList);
                }
            }
            // 显示设置 替换attrName
            Map<String,String> namedMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            Map<String,String> namedSubMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            OuterLinkConfigEntity configEntity = outerLinkConfigService.getOuterLinkConfigEntities(corpid,formId,OuterLinkTypeEnum.WRITE.getCode(),OutLinkSettingTypeEnum.DISPLAY_SETTING.getCode());
            if (Objects.nonNull(configEntity)){
                String explains = configEntity.getExplains();
                List<OutLinkFieldAttrEntity> outLinkFieldAttrEntities = JSONArray.parseArray(explains,OutLinkFieldAttrEntity.class);
                for (int i = 0; i < outLinkFieldAttrEntities.size(); i++) {
                    OutLinkFieldAttrEntity entity = outLinkFieldAttrEntities.get(i);
                    if (ExplainUtil.isSubFormNoSelectProduct(entity.getFieldType())){
                        List<? extends OutLinkFieldAttrEntity> subExplainList = entity.getSubForm().getItems();
                        if (Objects.nonNull(subExplainList)){
                            for (int j = 0; j < subExplainList.size(); j++) {
                                OutLinkFieldAttrEntity value = subExplainList.get(j);
                                if (Objects.equals(value.getRenamed(),1)){
                                    namedSubMap.put(entity.getAttr() + "." + value.getAttr(),value.getDefaultName());
                                }
                            }
                        }
                    }
                    if (Objects.equals(entity.getRenamed(),1)){
                        namedMap.put(entity.getAttr(),entity.getDefaultName());
                    }
                }
                if (StringUtil.isNotEmpty(configEntity.getDefaultFormName()) ){
                    paasFormEntityExt.setName(configEntity.getDefaultFormName());
                }
            }
            for (int i = 0; i < explainList.size(); i++) {
                FieldAttrEntity fieldAttrEntity = explainList.get(i);
                if (ExplainUtil.isSubFormNoSelectProduct(fieldAttrEntity.getFieldType())){
                    List<? extends FieldAttrEntity> subExplainList = fieldAttrEntity.getSubForm().getItems();
                    if (Objects.nonNull(subExplainList)){
                        for (int j = 0; j < subExplainList.size(); j++) {
                            FieldAttrEntity fieldAttr = subExplainList.get(j);
                            if (namedSubMap.containsKey(fieldAttrEntity.getAttr() + "." + fieldAttr.getAttr())){
                                fieldAttr.setAttrName(namedSubMap.getOrDefault(fieldAttrEntity.getAttr() + "." + fieldAttr.getAttr(),""));
                            }
                        }
                    }
                    fieldAttrEntity.getSubForm().setItems(subExplainList);
                }
                if (namedMap.containsKey(fieldAttrEntity.getAttr())){
                    fieldAttrEntity.setAttrName(namedMap.getOrDefault(fieldAttrEntity.getAttr(),""));
                }
            }

            // 查询客户名称和电话判重设置
            if ( Objects.equals(businessType, XbbRefTypeEnum.CUSTOMER_MANAGEMENT.getCode()) ) {
                handlerCustomerRepeat(corpid, formId, explainList);
            }
            String serialNo = "";
            if (!Objects.equals(outerLinkAddGetDTO.getOuterShow(), BasicConstant.ONE)) {
                // 外观设置请求该接口不对流水号做处理，防止跳号
                for (FieldAttrEntity fieldAttrEntity : explainList) {
                    // 获取流水号
                    if (Objects.equals(fieldAttrEntity.getAttr(), FieldTypeEnum.SERIALNO.getAlias()) && Objects.equals(fieldAttrEntity.getStrictController(), BasicConstant.ZERO)) {
                        serialNo = saasSaveHelp.getSerialNo(serialNo, corpid, formId, fieldAttrEntity);
                    }
                    // fix:18442 【移动端、web端】新建、编辑页面，不展示系统自动生成字段
                    if (Objects.equals(fieldAttrEntity.getUnableEditMemo(), I18nMessageUtil.getMessage(StringConstant.AUTO_GEN_FIELD))) {
                        fieldAttrEntity.setVisible(0);
                    }
                }
                if (Objects.equals(businessType, XbbRefTypeEnum.QUOTATION.getCode())) {
                    // 报价单编号是组号加版本号
                    formDataAddGetVO.setGroupNumber(serialNo);
                    serialNo = serialNo + StringConstant.DEFAULT_VERSION;
                }
            }
            formDataAddGetVO.setSerialNo(serialNo);

            // 获取字段解释信息，并且过滤不可见字段 end
            // 新建表单时SaaS某些字段赋初始值
            if ( Objects.equals(1, SaasMarkEnum.SAAS.getCode()) ) {

                FormatExplainDTO formatExplainDTO = new FormatExplainDTO();
                BeanUtil.copyProperties(outerLinkAddGetDTO, formatExplainDTO);
                formatExplainDTO.setExplainList(explainList);

                //saasAddHelp.formatExplain(formatExplainDTO);
                formDataAddGetVO.setExplainList(formatExplainDTO.getExplainList());
                // saas特殊返回字段，放在一个对象中
                //saasAddHelp.formatSaasAttrToReturn(formDataAddGetVO, outerLinkAddGetDTO);
                explainList = formDataAddGetVO.getExplainList();
            }
            formDataAddGetVO.setExplainList(explainList);
            OuterLinkAppearanceGetDTO outerLinkAppearanceGetDTO = new OuterLinkAppearanceGetDTO();
            outerLinkAppearanceGetDTO.setCorpid(corpid);
            outerLinkAppearanceGetDTO.setFormId(formId);
            OuterLinkAppearanceGetVO appearance = outerLinkConfigService.getAppearance(outerLinkAppearanceGetDTO);
            JSONObject appearanceObj = new JSONObject();
            appearanceObj.put("themeList", appearance.getThemeList());
            appearanceObj.put("configInfo", appearance.getConfigInfo());
            appearanceObj.put("initFlag", appearance.getInitFlag());
            formDataAddGetVO.setOuterLinkAppearance(appearanceObj);
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("paasFormData数据库查询表单数据出错", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return formDataAddGetVO;
    }

    /**
     *
     * @param corpid
     * @param formId
     * @param explainList
     */
    private void handlerCustomerRepeat(String corpid, Long formId, List<FieldAttrEntity> explainList) {
        String nameRepeat = FormConfigEnum.CUSTOMER_NAME_REPEAT_TYPE.getConfig();
        String phoneRepeat = FormConfigEnum.CUSTOMER_PHONE_REPEAT_TYPE.getConfig();
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", corpid);
        param.put("formId", formId);
        param.put("configIn", Arrays.asList(nameRepeat, phoneRepeat));
        param.put("del", DelEnum.NORMAL.getDel());
        List<FormConfigEntity> formConfigEntityList = formConfigModel.findEntitys(param);
        Map<String, String> formConfigMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for ( FormConfigEntity configEntity : formConfigEntityList ) {
            formConfigMap.put(configEntity.getConfig(), configEntity.getConfigValue());
        }

        if ( Objects.nonNull(formConfigMap.get(nameRepeat)) ) {
            for ( FieldAttrEntity fieldAttrEntity : explainList ) {
                if ( Objects.equals(fieldAttrEntity.getAttr(), CustomerManagementEnum.NAME.getAttr()) ) {
                    // 根据表单配置更改 noRepeat 的值(不启用时noRepeat为0，模板内和全局时noRepeat为1)
                    if ( Objects.equals(formConfigMap.get(nameRepeat), RepeatTypeEnum.REPEAT_CANCEL.getType().toString()) ) {
                        fieldAttrEntity.setNoRepeat(RepeatTypeEnum.REPEAT_CANCEL.getType());
                    } else {
                        fieldAttrEntity.setNoRepeat(RepeatTypeEnum.REPEAT_SINGLE.getType());
                    }
                    break;
                }
            }
        }

        if ( Objects.nonNull(formConfigMap.get(phoneRepeat)) ) {
            for ( FieldAttrEntity fieldAttrEntity : explainList ) {
                if ( Objects.equals(fieldAttrEntity.getAttr(), CustomerManagementEnum.PHONE.getAttr()) ) {
                    List<? extends FieldAttrEntity> items = fieldAttrEntity.getSubForm().getItems();
                    for ( FieldAttrEntity item : items ) {
                        if ( Objects.equals(item.getAttr(), "text_2") ) {
                            // 根据表单配置更改 noRepeat 的值(不启用时noRepeat为0，模板内和全局时noRepeat为1)
                            if ( Objects.equals(formConfigMap.get(phoneRepeat), RepeatTypeEnum.REPEAT_CANCEL.getType().toString()) ) {
                                item.setNoRepeat(RepeatTypeEnum.REPEAT_CANCEL.getType());
                            } else {
                                item.setNoRepeat(RepeatTypeEnum.REPEAT_SINGLE.getType());
                            }
                        }
                    }
                    break;
                }
            }
        }
    }


    /**
     * 校验并解析token 解析出businessType corpid formId expandField
     * @param
     * @param token
     * @param
     * @throws XbbException
     */
    @Override
    public OuterLinkEntity getTokenByType(String token,Integer type) throws XbbException{
        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put("hashCode", token);
        params.put("del", 0);
//        params.put("enable",1);
        params.put("type",type);
        List<OuterLinkEntity> outerLinkEntityList = outerLinkModel.findEntitys(params);
        if (CollectionsUtil.isEmpty(outerLinkEntityList)){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405006);
        }
//        // 外链填写有拓展链接 外面关闭 里面的链接也应失效
        if (Objects.equals(type,OuterLinkTypeEnum.WRITE.getCode())) {
            for (int i = 0; i < outerLinkEntityList.size(); i++) {
                OuterLinkEntity outerLinkEntity = outerLinkEntityList.get(i);
                if (Objects.nonNull(outerLinkEntity.getAttr()) || Objects.nonNull(outerLinkEntity.getExpandField())) {
                    Integer businessType = outerLinkEntity.getBusinessType();
                    Long formId = outerLinkEntity.getFormId();
                    String corpid = outerLinkEntity.getCorpid();
                    params.clear();
                    params.put("businessType", businessType);
                    params.put("del", 0);
                    params.put("formId", formId);
                    params.put("corpid", corpid);
                    params.put("type", OuterLinkTypeEnum.WRITE.getCode());
                    params.put("excludeExpandField", "excludeExpandField");
                    List<OuterLinkEntity> outerLinkEntityLists = outerLinkModel.findEntitys(params);
                    if (Objects.nonNull(outerLinkEntityLists)) {
                        if (Objects.equals(outerLinkEntityLists.get(0).getEnable(), 0)) {
                            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405010);
                        }
                    }
                    return outerLinkEntity;
                }
            }
        }
        if (Objects.equals(outerLinkEntityList.get(0).getEnable(),0)){
            throw new XbbException(OutLinkErrorCodeEnum.API_ERROR_405010);
        }
        return outerLinkEntityList.get(0);
    }
    
    /**
     * 外链筛选仅支持单行文本、单选按钮、下拉框、地址、流水号、数字、日期、标签
     * 其中，数字和日期都是范围筛选，其它都是等于
     *
     * @author long.rao
     * @date 2020-08-20 17:21
     */
    private Map<String, List<ConditionClass>> getConditionList() {
        Map<String, List<ConditionClass>> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        ConditionClass equalCondition = new ConditionClass();
        equalCondition.setSymbol(ConditionEnum.EQUAL.getSymbol());
        equalCondition.setReplaceSymbol(ConditionEnum.EQUAL.getReplaceSymbol());
        equalCondition.setMemo(ConditionEnum.EQUAL.getMemo());

        ConditionClass rangeCondition = new ConditionClass();
        rangeCondition.setSymbol(ConditionEnum.RANGE.getSymbol());
        rangeCondition.setReplaceSymbol(ConditionEnum.RANGE.getReplaceSymbol());
        rangeCondition.setMemo(ConditionEnum.RANGE.getMemo());
        map.put(FieldTypeEnum.TEXT.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.RADIO_GROUP.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.COMBO.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.ADDRESS.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.SERIALNO.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.COMBO_CHECK.getType().toString(), Arrays.asList(equalCondition));
        map.put(FieldTypeEnum.LABEL.getType().toString(), Arrays.asList(equalCondition));

        map.put(FieldTypeEnum.NUM.getType().toString(), Arrays.asList(rangeCondition));
        map.put(FieldTypeEnum.DATETIME.getType().toString(), Arrays.asList(rangeCondition));

        return map;
    }
}
